package net.homeip.jcperera.nu.core.msg;

import java.io.Serializable;
import java.util.Vector;
import java.util.logging.Level;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.spi.Bean;
import javax.faces.context.FacesContext;
import javax.inject.Named;

import net.homeip.jcperera.nu.core.CoreBase;
import net.homeip.jcperera.nu.core.boot.Boot;
import net.homeip.jcperera.nu.core.config.Configuration;

/**
 * <p>
 * Session Bean implementation class Logger.
 * </p>
 * <p>
 * Keeps the logging configuration and also refreshes it when required, all requests to logging services and
 * configuration must be done using methods from this {@link Bean}
 * </p>
 * 
 * @name General Logging Bean
 * @author julio.c.perera@gmail.com
 * @application nu
 * @since 0.1.0.0
 */

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
@LocalBean
@ApplicationScoped
@Named(Logging.componentName)
public class Logging extends CoreBase implements Serializable
{
    // Required to implement Serializable interface
    private static final long    serialVersionUID       = 5540647752301189835L;

    // CoreBase properties, for easy use from other components, as well as logging
    public static final int      runtimeLevel           = 0;
    public static final String   moduleName             = "core";
    public static final String   componentName          = "nu_core_logging_bean";

    // Internal status and configuration properties
    public static final String   enabledProperty        = "nu.core.msg.logging.lines.enable";
    private static final boolean enabledDefaultValue    = true;
    private boolean              enabled                = enabledDefaultValue;

    public static final String   linesLimitProperty     = "nu.core.msg.logging.lines.limit";
    private static final short   linesLimitDefaultValue = 1000;
    private short                linesLimit             = linesLimitDefaultValue;
    private static final String  facesSystemClientId    = "system";
    
    private Vector<LogLine>      lines                  = new Vector<LogLine>();

    // Get the log
    private static final Logger  log                    = Logger.getLogger();

    public Logging()
    {
    }

    public void start() throws BaseMessage
    {
        log.info("Starting Logging Service...");
        reloadConfig();
    }

    public void stop()
    {
        log.info("Stopping Logging Service...");
        lines.clear();
    }

    public void reloadConfig() throws BaseMessage
    {
        Configuration configuration = Boot.getSystem().getConfiguration();

        // Process enabled setting from config
        String enableStr = configuration.getAndPutIfNotExists(enabledProperty, Boolean.toString(enabledDefaultValue));
        setEnabled(enableStr.equalsIgnoreCase("true") || enableStr.equals("1"));

        String linesLimitStr = configuration.getAndPutIfNotExists(linesLimitProperty,
                Short.toString(linesLimitDefaultValue));
        setLinesLimit(Short.decode(linesLimitStr));
    }

    public short getLinesLimit()
    {
        return linesLimit;
    }

    public void setLinesLimit(short linesLimit) throws BaseMessage
    {
        if (linesLimit > 0) this.linesLimit = linesLimit;
        else throw new ErrorMessage("nu.core.msg.logging.lines.invalid.limit", BaseMessage.FRIENDLINESS_FRIENDLY);
    }

    public boolean isEnabled()
    {
        return enabled;
    }

    public void setEnabled(boolean enabled)
    {
        if (!this.enabled && enabled) lines.clear();
        this.enabled = enabled;
    }

    /**
     * Adds a new <code>line</code> to the <code>lines</code> collection.
     * 
     * @param logline
     *            The line to be added
     */
    public void addLine(Level level, String logline)
    {
        addLine(level, logline, null);
    }

    /**
     * Adds a new <code>line</code> to the <code>lines</code> collection.
     * 
     * @param logline
     *            The line to be added
     */
    public void addLine(Level level, String logline, Object param1)
    {
        addLine(level, logline, new Object[] { param1 });
    }

    /**
     * Adds a new <code>line</code> to the <code>lines</code> collection.
     * 
     * @param logline
     *            The line to be added
     */
    public void addLine(Level level, String logline, Object[] params)
    {
        if (enabled)
        {
            int size = lines.size();
            if (size >= linesLimit) lines.remove(0);
            lines.add(new LogLine(level, logline, params));
        }
    }

    /**
     * Gets the collection of last logged lines (depend on the configured limit).
     * 
     * @return a {@link Vector} of these lines
     */
    public Vector<LogLine> getLines()
    {
        return lines;
    }

    /**
     * Adds all messages in the {@code System Messages Vector} to the provided {@link FacesContext}
     * 
     * @param facesContext
     *            The {@link FacesContext} to add the {@code System Messages}
     */
    public void addAllSystemMessagesToFacesContext(FacesContext facesContext)
    {
        for (LogLine line : lines)
        {
            line.addMessageToFacesContext(facesSystemClientId,facesContext);
        }
    }
}
